/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import {
  ClassSignature,
  MethodSignature,
  Stmt,
  ArkAssignStmt,
  Local,
  Value,
  ArkInvokeStmt,
  FieldSignature,
  AbstractBinopExpr,
  ExportInfo,
  AstTreeUtils,
  AliasType,
  ArkAliasTypeDefineStmt,
  Scene,
  LineColPosition,
  ts,
  ArkFile,
  ImportInfo,
} from "arkanalyzer/lib";
import { RuleListUtil } from "../../utils/common/DefectsList";
import { ArkClass } from "arkanalyzer/lib/core/model/ArkClass";
import Logger, { LOG_MODULE_TYPE } from "arkanalyzer/lib/utils/logger";
import { BaseChecker, BaseMetaData } from "../BaseChecker";
import {
  FileMatcher,
  MatcherCallback,
  MatcherTypes,
} from "../../matcher/Matchers";
import { Defects, IssueReport } from "../../../src/model/Defects";
import { Rule } from "../../model/Rule";
type Scene_base = {
  declaringStmt?: Stmt;
  fieldSignature?: FieldSignature;
  classSignature?: ClassSignature;
  methodSignature?: MethodSignature;
  classType?: { classSignature?: ClassSignature };
};
//结果类型
enum VarType {
  Var = "var",
  TypeDef = "typeDef",
  TypeRef = "typeRef",
  ENUM = "enum",
  Class = "class",
  Method = "method",
  Param = "param",
  Export = "export",
}
type UseDefined = {
  varType: VarType; //方法名称
  stmt?: Stmt;
  arkClass?: ArkClass;
  exportinfo?: ExportInfo;
  filePath?: string;
  posion?: [lineNo: number, column: number];
  infunc?: boolean;
  name: string; //解构-特殊情况
};
type Options = {
  allowNamedExports?: boolean;
  classes?: boolean;
  enums?: boolean;
  functions?: boolean;
  variables?: boolean;
  ignoreTypeReferences?: true;
  typedefs?: true;
};
const defaultOptions: Options = {
  allowNamedExports: false,
  classes: true,
  enums: true,
  functions: true,
  variables: true,
  ignoreTypeReferences: true,
  typedefs: true,
};

const logger = Logger.getLogger(
  LOG_MODULE_TYPE.HOMECHECK,
  "NoUseBeforeDefineCheck"
);
const gMetaData: BaseMetaData = {
  ruleId: "@typescript-eslint/no-use-before-define-check",
  severity: 1,
  ruleDocPath: "docs/no-use-before-define-check.md",
  description: " was used before it was defined.",
};
//编译过程中检测未使用的本地变量和参数
export class NoUseBeforeDefineCheck implements BaseChecker {
  readonly metaData: BaseMetaData = gMetaData;
  readonly SHORT_STR: string = "sort";
  public rule: Rule;
  public defects: Defects[] = [];
  public issues: IssueReport[] = [];
  private clsMatcher: FileMatcher = {
    matcherType: MatcherTypes.FILE,
  };

  public registerMatchers(): MatcherCallback[] {
    const matchBuildCb: MatcherCallback = {
      matcher: this.clsMatcher,
      callback: this.check,
    };
    return [matchBuildCb];
  }

  public check = (targetFile: ArkFile) => {
    const filePath = targetFile.getName();
    const isTs = this.getFileExtension(filePath, "ts");
    if (!isTs) {
      return;
    }
    /**
     * targetClass 是扫描的目标文件Class类
     * methods 是文件内所有定义的函数(函数-->'%dft'--->文件非定义Class 和function 片段)
     *
     */
    const scene = targetFile.getScene();
    let astRoot = AstTreeUtils.getASTNode(
      targetFile.getName(),
      targetFile.getCode()
    );
    const unUsedClass = this.findClassUsageErrors(astRoot);

    //获取定义之前
    //获取定义在arkfile最外层的变量集合
    const allVar: UseDefined[] = []; //存放全局变量信息;
    let usedBefores: UseDefined[] = [];
    const defaultMethod = targetFile.getDefaultClass().getDefaultArkMethod();
    if (defaultMethod) {
      const vstmts = defaultMethod.getBody()?.getCfg().getStmts() ?? [];
      for (const stmt of vstmts) {
        if (stmt instanceof ArkAssignStmt) {
          const varName = stmt.getLeftOp().toString();
          if (!varName.startsWith("this") || !varName.startsWith("%")) {
            allVar.push({
              varType: VarType.Var,
              stmt: stmt,
              name: varName,
            });
          }
        }
      }
    }
    //获取定义在全局的type
    const globalAliasTypeMapMap:
      | Map<string, [AliasType, ArkAliasTypeDefineStmt]>
      | undefined = targetFile
      .getDefaultClass()
      .getDefaultArkMethod()
      ?.getBody()
      ?.getAliasTypeMap();
    const importInfos = targetFile.getImportInfos();
    for (const targetClass of targetFile.getClasses()) {
      const methods = targetClass.getMethods();
      const extendClass: Map<string, ArkClass> =
        targetClass.getExtendedClasses();
      for (const [key, extendArkclass] of extendClass) {
        if (extendArkclass) {
          //1.推断类是否之前调
          const column = extendArkclass?.getColumn() ?? -1;
          const line = extendArkclass?.getLine() ?? -1;
          const targetClassLine = targetClass?.getLine() ?? -1;
          const result = importInfos.find((item) => {
            item.getImportClauseName() === extendArkclass?.getName();
          });
          if (targetClassLine < line && !result) {
            //添加到结果集
            usedBefores.push({
              varType: VarType.Class,
              arkClass: targetClass,
              name: extendArkclass?.getName() ?? "",
            });
          }
        }
      }

      for (const arkMethod of methods) {
        const stmts = arkMethod.getBody()?.getCfg().getStmts() ?? [];
        const usedGlobal: Map<string, Value> =
          arkMethod.getBody()?.getUsedGlobals() ?? new Map<string, Value>();
        const varLocal: Map<string, Local> =
          arkMethod.getBody()?.getLocals() ?? new Map<string, Local>();
        for (const [key, local] of varLocal) {
          const declareStmt = local.getDeclaringStmt();
          if (declareStmt instanceof ArkAssignStmt) {
            const leftOp = declareStmt.getLeftOp();
            const typeName =
              leftOp.getType().toString().split("#").at(-1) ??
              leftOp.getType().toString();
            const localAliasTypeMapMap:
              | Map<string, [AliasType, ArkAliasTypeDefineStmt]>
              | undefined = targetFile
              .getDefaultClass()
              .getDefaultArkMethod()
              ?.getBody()
              ?.getAliasTypeMap();
            // 不解析this
            if (leftOp.toString().startsWith("this")) {
              continue;
            }
            if (localAliasTypeMapMap && localAliasTypeMapMap.has(typeName)) {
              const aliasTypeDeclaration = localAliasTypeMapMap.get(typeName);
              if (aliasTypeDeclaration) {
                const aliasTypeDecl = aliasTypeDeclaration[1];
                const lineNo = aliasTypeDecl
                  .getOriginPositionInfo()
                  .getLineNo();
                const declareLine = declareStmt
                  .getOriginPositionInfo()
                  .getLineNo();
                if (declareLine < lineNo) {
                  usedBefores.push({
                    varType: VarType.TypeDef,
                    stmt: declareStmt,
                    name: typeName ?? "",
                  });
                }
              }
            } else if (
              globalAliasTypeMapMap &&
              globalAliasTypeMapMap.has(typeName)
            ) {
              const globalTypeDeclaration = globalAliasTypeMapMap.get(typeName);
              if (globalTypeDeclaration) {
                const aliasTypeDecl = globalTypeDeclaration[1];
                const lineNo = aliasTypeDecl
                  .getOriginPositionInfo()
                  .getLineNo();
                const declareLine = declareStmt
                  .getOriginPositionInfo()
                  .getLineNo();
                if (declareLine < lineNo) {
                  usedBefores.push({
                    varType: VarType.TypeDef,
                    arkClass: targetClass,
                    name: typeName ?? "",
                  });
                }
              }
            } else if (
              importInfos &&
              importInfos.find(
                (item) => item.getImportClauseName() === typeName
              )
            ) {
              const lineNo =
                importInfos
                  .find((item) => item.getImportClauseName() === typeName)
                  ?.getOriginTsPosition()
                  .getLineNo() ?? -1;
              const declareLine = declareStmt
                .getOriginPositionInfo()
                .getLineNo();
              if (declareLine < lineNo) {
                usedBefores.push({
                  varType: VarType.TypeDef,
                  arkClass: targetClass,
                  name: typeName ?? "",
                });
              }
            }
          }
        }
        for (const [key, glob] of usedGlobal) {
          const usedGlobalName = key;
          const varAll = allVar.find((item) => item.name === usedGlobalName);
          const usedStmt = (glob as { usedStmts?: Stmt[] }).usedStmts ?? [];
          for (const usestm of usedStmt) {
            if (varAll) {
              const lineNo = usestm.getOriginPositionInfo().getLineNo() ?? -1;
              const varLine =
                varAll.stmt?.getOriginPositionInfo().getLineNo() ?? -1;
              if (varLine > lineNo) {
                usedBefores.push({
                  varType: VarType.Var,
                  stmt: usestm,
                  name: usedGlobalName ?? "",
                });
              }
            }
          }
        }
        //检索执行语句(函数调用)
        for (const stmt of stmts) {
          //1.非执行语句
          if (stmt instanceof ArkAssignStmt) {
            const leftOp = stmt.getLeftOp();
            const rightOp = stmt.getRightOp();
            // 不解析this
            if (leftOp.toString().startsWith("this")) {
              continue;
            }

            // 处理右操作符
            const leftStmt = (leftOp as Scene_base).declaringStmt;
            if (leftStmt) {
              const usedBefore = this.handleRightOp(
                leftStmt,
                rightOp,
                scene,
                importInfos
              );
              const result = importInfos.find(
                (item) => item.getImportClauseName() === usedBefore.name
              );
              if (
                usedBefore.name !== "" &&
                !usedBefore.name.startsWith("%") &&
                !result
              ) {
                usedBefores.push(usedBefore);
              }
            }
          }
          //1.判断执行函数是否在定义之前+参数

          if (stmt instanceof ArkInvokeStmt) {
            //
            const line = stmt.getOriginPositionInfo().getLineNo();

            const arkMethod = scene.getMethod(
              stmt.getInvokeExpr().getMethodSignature()
            );
            // const mapLKey=   stmt.getInvokeExpr().getMethodSignature().toMapKey();
            // const useds=   stmt.getUses();
            // const useds2=   stmt.getUses().toString();
            //如果存在调用链
            const linkCode = stmt?.getOriginalText() ?? "";
            const linkFirst = this.extractFunctionName(linkCode);
            const methodName = arkMethod?.getName() ?? "-1-1";
            const result = importInfos.find((item) => {
              const name = item.getImportClauseName();
              return name === methodName || name === linkFirst;
            });
            const methodClass = arkMethod
              ?.getDeclaringArkClass()
              ?.getSignature();
            const thisClass = stmt
              .getCfg()
              ?.getDeclaringMethod()
              ?.getDeclaringArkClass()
              ?.getSignature();
            const BtoB = methodClass === thisClass;
            const methodLine = arkMethod?.getLine() ?? -1;
            if (
              !methodName.startsWith("%") &&
              (!linkFirst || (BtoB && methodLine > line && !result))
            ) {
              usedBefores.push({
                varType: VarType.Method,
                stmt: stmt,
                name: methodName,
              });
            }
            const parameters = stmt.getInvokeExpr().getArgs();
            for (const param of parameters) {
              const paramName = param.toString();
              const varAll = allVar.find((item) => item.name === paramName);
              if (varAll) {
                const lineP =
                  varAll.stmt?.getOriginPositionInfo().getLineNo() ?? -1;
                if (lineP > line) {
                  const invokeCode = stmt?.getOriginalText() ?? "";
                  let col = stmt?.getOriginPositionInfo()?.getColNo() ?? -1;
                  const posion = this.getAccuratePosition(
                    invokeCode,
                    paramName
                  );
                  let colNo = posion.col;
                  if (!invokeCode.startsWith(" ")) {
                    colNo = col + colNo;
                  }
                  usedBefores.push({
                    varType: VarType.Param,
                    stmt: stmt,
                    posion: [line, colNo],
                    name: paramName ?? "",
                  });
                }
              }
            }
          }
        }
      }
    }
    //2.导出类型判定
    const exports: ExportInfo[] = targetFile.getExportInfos();
    for (const exp of exports) {
      const line = exp.getOriginTsPosition().getLineNo();
      const sourLine =
        (exp.getArkExport() as Scene_base)?.declaringStmt
          ?.getOriginPositionInfo()
          .getLineNo() ?? -1;
      if (sourLine > line) {
        usedBefores.push({
          varType: VarType.Export,
          exportinfo: exp,
          name: exp.getExportClauseName(),
        });
      }
    }

    const options: Options = this.rule.option[0] as unknown as Options;
    const mergedOptions: Options = {
      ...defaultOptions,
      ...options,
    };

    //装配未使用的class
    const collects = [
      "Map",
      "Set",
      "WeakMap",
      "WeakSet",
      "Array",
      "Object",
      "List",
    ];
    for (const [key, value] of unUsedClass) {
      const result = importInfos.find((item) => {
        const importName = item.getImportClauseName();
        return importName === key;
      });

      if (!result && !collects.includes(key)) {
        usedBefores.push({
          varType: VarType.Class,
          name: key,
          filePath: targetFile.getFilePath(),
          posion: [value.line, value.column],
          infunc: value.inFun,
        });
      }
    }

    const filerUsed = this.filterUnuseds(mergedOptions, usedBefores);
    for (const info of filerUsed) {
      if (info.arkClass) {
        this.addIssueReportOther(
          info.name,
          info.arkClass.getCode() ?? "",
          info.arkClass.getDeclaringArkFile(),
          [info.arkClass.getLine(), info.arkClass.getColumn()]
        );
      } else if (info.exportinfo) {
        const position = info.exportinfo.getOriginTsPosition();
        this.addIssueReportOther(
          info.name,
          info.exportinfo.getTsSourceCode() ?? "",
          info.exportinfo.getDeclaringArkFile(),
          [position.getLineNo(), position.getColNo()]
        );
      } else if (info.stmt && info.varType === VarType.Param) {
        //方便缩小检查范围
        this.addIssueReport(info.stmt, info.name, true);
      } else if (info.stmt) {
        this.addIssueReport(info.stmt, info.name, false);
      } else if (info.posion) {
        this.addIssueReportOther(
          info.name,
          "",
          info?.filePath ?? "",
          info.posion
        );
      }
    }
  };
  private handleRightOp(
    leftOp: Stmt,
    rightOp: any,
    scene: Scene,
    importInfos: ImportInfo[]
  ): UseDefined {
    let useDefinedBefore: UseDefined = {
      varType: VarType.Var,
      stmt: leftOp,
      name: "",
    };
    if (rightOp instanceof AbstractBinopExpr) {
      const op1 = rightOp.getOp1();
      const op2 = rightOp.getOp2();
      if (!op1.toString().startsWith("%")) {
        useDefinedBefore = this.processExpression(
          leftOp,
          op1,
          scene,
          importInfos
        ); // 处理 op1
      }
      if (!op2.toString().startsWith("%")) {
        useDefinedBefore = this.processExpression(
          leftOp,
          op2,
          scene,
          importInfos
        ); // 处理 op2
      }
    } else if (!rightOp.toString().startsWith("%")) {
      useDefinedBefore = this.processExpression(
        leftOp,
        rightOp,
        scene,
        importInfos
      ); //直接处理
    }
    return useDefinedBefore;
  }
  private processExpression(
    leftOp: Stmt,
    expr: any,
    scene: Scene,
    importInfos: ImportInfo[]
  ): UseDefined {
    let useDefinedBefore: UseDefined = {
      varType: VarType.Var,
      stmt: leftOp,
      name: "",
    };
    const exprDef = expr as Scene_base;

    let lineNo = leftOp.getOriginPositionInfo().getLineNo() ?? -1;
    //记录原始对比信息
    //1.处理变量
    if (exprDef.declaringStmt) {
      // 判断调用变量是否在定义之后
      // 加入到结果池中
      const declareStmt = exprDef.declaringStmt;
      const line = declareStmt.getOriginPositionInfo().getLineNo();
      if (declareStmt instanceof ArkAssignStmt && lineNo < line) {
        //添加到结果集
        const name = declareStmt.getLeftOp().toString() ?? "";
        useDefinedBefore = {
          varType: VarType.ENUM,
          stmt: leftOp,
          name: name,
        };
      }
    } else if (exprDef.fieldSignature) {
      //2.处理枚举
      const fieldSignature = exprDef.fieldSignature;
      const classSignature = (fieldSignature.getType() as Scene_base)
        .classSignature;
      if (classSignature) {
        const arkClass = scene.getClass(classSignature);
        const column = arkClass?.getColumn();
        const line = arkClass?.getLine() ?? -1;
        const thisClass = leftOp
          .getCfg()
          ?.getDeclaringMethod()
          ?.getDeclaringArkClass()
          ?.getSignature();
        const classSign = arkClass?.getSignature();
        const BtoB = classSign === thisClass;
        if (lineNo < line && BtoB) {
          //添加到结果集
          useDefinedBefore = {
            varType: VarType.ENUM,
            stmt: leftOp,
            name: arkClass?.getName() ?? "",
          };
        }
        const io = line;
      }
    } else if (exprDef.methodSignature) {
      //3.处理函数
      const methodSignature = exprDef.methodSignature;

      if (methodSignature) {
        const methodName1 =
          methodSignature?.getMethodSubSignature()?.getMethodName() ?? "-1-1";
        const arkMethod = scene.getMethod(methodSignature);
        const line = arkMethod?.getLine() ?? -1;
        const io = line;
        const methodName = arkMethod?.getName() ?? methodName1;
        const originalText = leftOp.getOriginalText() ?? "";
        lineNo = leftOp?.getOriginPositionInfo()?.getLineNo();
        const linkFirst = this.extractFunctionName(originalText);
        const result = importInfos.find((item) => {
          const name = item.getImportClauseName();
          return name === methodName || name === linkFirst;
        });
        const methodClass = arkMethod?.getDeclaringArkClass()?.getSignature();
        const thisClass = leftOp
          .getCfg()
          ?.getDeclaringMethod()
          ?.getDeclaringArkClass()
          ?.getSignature();
        const BtoB = methodClass === thisClass;
        if (
          !methodName.startsWith("%") &&
          (!linkFirst || (BtoB && lineNo < line && !result))
        ) {
          //添加到结果集
          useDefinedBefore = {
            varType: VarType.Method,
            stmt: leftOp,
            name: arkMethod?.getName() ?? "",
          };
        }
      }
    } else if (exprDef.classSignature || exprDef.classType) {
      //3.处理类
      const classSignature =
        exprDef.classSignature ?? exprDef.classType?.classSignature;
      if (classSignature) {
        const arkClass = scene.getClass(classSignature);
        const column = arkClass?.getColumn() ?? -1;
        const line = arkClass?.getLine() ?? -1;
        const result = importInfos.find((item) => {
          const name = item.getImportClauseName();
          const className = arkClass?.getName();
          return name === className;
        });

        if (lineNo < line && !result) {
          //添加到结果集
          useDefinedBefore = {
            varType: VarType.Class,
            stmt: leftOp,
            name: arkClass?.getName() ?? "",
          };
        }
        const io = line;
      }
    }
    return useDefinedBefore;
  }
  //获取过滤后的结果
  private filterUnuseds(
    mergedOptions: Options,
    usedBefores: UseDefined[]
  ): UseDefined[] {
    let filerUse: UseDefined[] = [];
    if (mergedOptions.classes) {
      usedBefores = usedBefores.filter(
        (item) => !(item.varType === VarType.Class && item.infunc)
      );
    } else if (mergedOptions.functions) {
      usedBefores = usedBefores.filter(
        (item) => !(item.varType === VarType.Method)
      );
    } else if (mergedOptions.variables) {
      usedBefores = usedBefores.filter(
        (item) => !(item.varType === VarType.Var)
      );
    } else if (mergedOptions.allowNamedExports) {
      usedBefores = usedBefores.filter(
        (item) => !(item.varType === VarType.Export)
      );
    }
    filerUse = usedBefores;
    return filerUse;
  }
  private addIssueReport(stmt: Stmt, name: string, isparam: boolean) {
    const severity = this.rule.alert ?? this.metaData.severity;
    const level = severity === 2 ? "error" : "warn";
    let warnInfo = this.getLineAndColumn(stmt, name, isparam);
    if (isparam) {
      warnInfo.startCol = warnInfo.endCol;
    }
    const fixKey =
      warnInfo.line + "%" + warnInfo.startCol + "%" + this.rule.ruleId;
    const mergeKey =
      warnInfo.filePath + "%" + fixKey + "%" + this.metaData.description;
    const defect = new Defects(
      warnInfo.line,
      warnInfo.startCol,
      `'${name}' ` + this.metaData.description,
      severity,
      this.rule.ruleId,
      mergeKey,
      this.metaData.ruleDocPath,
      true,
      false,
      false,
      fixKey
    );
    if (warnInfo.line != -1) {
      this.defects.push(defect);
      this.issues.push(new IssueReport(defect, undefined));
      RuleListUtil.push(defect);
    }
  }

  private getLineAndColumn(stmt: Stmt, name: string, isparam: boolean) {
    const originPosition = stmt.getOriginPositionInfo();
    const line = originPosition.getLineNo();
    const arkFile = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile();
    if (arkFile) {
      const originText = stmt.getOriginalText() ?? "";
      let startCol = originPosition.getColNo();
      let pos = originText.indexOf(name);
      let indices = [];
      while (pos !== -1) {
        indices.push(pos);
        pos = originText.indexOf(name, pos + 1); // 继续查找下一个 目标
      }

      if (indices.length > 0) {
        if (isparam) {
          startCol = indices[indices.length - 1];
          const endCol = startCol + name.length - 1;
          const originPath = arkFile.getFilePath();
          return { line, startCol, endCol, filePath: originPath };
        } else {
          startCol += indices[0];
          const endCol = startCol + name.length - 1;
          const originPath = arkFile.getFilePath();
          return { line, startCol, endCol, filePath: originPath };
        }
      }
    } else {
      logger.debug("arkFile is null");
    }
    return { line: -1, startCol: -1, endCol: -1, filePath: "" };
  }
  private addIssueReportOther(
    name: string,
    code: string,
    arkfile: ArkFile | string,
    position: [lineNo: number, colNo: number]
  ) {
    const severity = this.rule.alert ?? this.metaData.severity;
    const level = severity === 2 ? "error" : "warn";
    let warnInfo = { line: -1, startCol: -1, endCol: -1, filePath: "" };
    if (arkfile instanceof ArkFile) {
      warnInfo = this.getLineAndColumnOther(name, code, arkfile, position);
    } else {
      warnInfo.filePath = arkfile;
      warnInfo.line = position[0];
      warnInfo.startCol = position[1];
    }
    const fixKey =
      warnInfo.line + "%" + warnInfo.startCol + "%" + this.rule.ruleId;
    const mergeKey =
      warnInfo.filePath + "%" + fixKey + "%" + this.metaData.description;
    const defect = new Defects(
      warnInfo.line,
      warnInfo.startCol,
      `'${name}' ` + this.metaData.description,
      severity,
      this.rule.ruleId,
      mergeKey,
      this.metaData.ruleDocPath,
      true,
      false,
      false,
      fixKey
    );
    if (warnInfo.line != -1) {
      this.defects.push(defect);
      this.issues.push(new IssueReport(defect, undefined));
      RuleListUtil.push(defect);
    }
  }
  private getLineAndColumnOther(
    name: string,
    code: string,
    arkfile: ArkFile,
    position: [lineNo: number, colNo: number]
  ) {
    if (arkfile) {
      const originText = code ?? "";
      let startCol = position[1];
      const pos = originText.indexOf(name);
      if (pos !== -1) {
        startCol += pos;
        const endCol = startCol + name.length - 1;
        const originPath = arkfile.getFilePath();
        return { line: position[0], startCol, endCol, filePath: originPath };
      }
    } else {
      logger.debug("arkFile is null");
    }
    return { line: -1, startCol: -1, endCol: -1, filePath: "" };
  }
  private findClassUsageErrors(
    astRoot: ts.SourceFile
  ): Map<string, { line: number; column: number; inFun: boolean }> {
    let classDeclarations = new Map<string, { line: number; column: number }>(); // 记录类的定义位置
    let errors = new Map<
      string,
      { line: number; column: number; inFun: boolean }
    >();
    const havBodyClass = this.getClassNames(astRoot); // 获取所有类名

    // 递归遍历 AST，记录所有 class 定义的位置
    const recordClassDeclarations = (node: ts.Node) => {
      // 处理类声明
      if (ts.isClassDeclaration(node) && node.name) {
        const className = node.name.text;
        const posion = LineColPosition.buildFromNode(node, astRoot);
        classDeclarations.set(className, {
          line: posion.getLineNo(),
          column: posion.getColNo() + 1,
        });
      }

      // 处理类表达式 (const C3 = class { ... })
      if (
        ts.isVariableDeclaration(node) &&
        ts.isIdentifier(node.name) &&
        node.initializer &&
        ts.isClassExpression(node.initializer)
      ) {
        const className = node.name.text;
        const posion = LineColPosition.buildFromNode(node, astRoot);
        classDeclarations.set(className, {
          line: posion.getLineNo(),
          column: posion.getColNo() + 1,
        });
        ts.forEachChild(node.initializer, (childNode) => {
          if (
            ts.isClassElement(childNode) ||
            ts.isMethodDeclaration(childNode) ||
            ts.isPropertyDeclaration(childNode)
          ) {
            const modifiers = ts.getCombinedModifierFlags(childNode);
            if ((modifiers & ts.ModifierFlags.Static) !== 0) {
              checkStaticPropertyInitializer(
                childNode,
                astRoot,
                className,
                errors
              );
            }
          }
        });
      }

      ts.forEachChild(node, recordClassDeclarations);
    };

    // 递归遍历 AST，检查类的使用是否在定义之前
    const checkClassUsage = (node: ts.Node) => {
      // 检查实例化时的类使用
      if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)) {
        const className = node.expression.text;
        const { line, character } = astRoot.getLineAndCharacterOfPosition(
          node.getStart()
        );
        const posion = LineColPosition.buildFromNode(node.expression, astRoot);

        // 获取当前节点的祖先
        let parent = node.parent;

        // 判断父节点是否是函数体内的节点
        let isInFunctionBody = false;
        while (parent) {
          if (ts.isFunctionLike(parent)) {
            isInFunctionBody = true;
            break;
          }
          parent = parent.parent;
        }
        if (
          !classDeclarations.has(className) ||
          classDeclarations.get(className)!.line > line
        ) {
          errors.set(className, {
            line: posion.getLineNo(),
            column: posion.getColNo(),
            inFun: isInFunctionBody,
          });
        }
      }

      // 检查继承的父类是否在定义之前使用
      if (ts.isClassDeclaration(node) && node.heritageClauses) {
        for (const heritageClause of node.heritageClauses) {
          for (const type of heritageClause.types) {
            if (ts.isIdentifier(type.expression)) {
              const superClassName = type.expression.text;
              const { line, character } = astRoot.getLineAndCharacterOfPosition(
                type.expression.getStart()
              );
              const posion = LineColPosition.buildFromNode(
                type.expression,
                astRoot
              );

              // 只对继承的类进行检查，如果父类未定义或者定义位置晚于子类，则报错
              if (
                !havBodyClass.includes(superClassName) ||
                !classDeclarations.has(superClassName) ||
                classDeclarations.get(superClassName)!.line > line
              ) {
                // 获取当前节点的祖先
                let isInFunctionBody = false;
                errors.set(superClassName, {
                  line: posion.getLineNo(),
                  column: posion.getColNo() + 1,
                  inFun: isInFunctionBody,
                });
              }
            }
          }
        }
      }

      // 检查类的计算属性名
      checkComputedPropertyUsage(node);

      // 检查静态块中的类使用
      checkStaticBlockUsage(node);

      // 检查类属性
      ts.forEachChild(node, checkClassUsage);
    };

    // 处理计算属性 [C1.x]
    const checkComputedPropertyUsage = (
      node: ts.Node,
      currentClassName: string | null = null
    ) => {
      if (ts.isClassDeclaration(node) && node.name) {
        currentClassName = node.name.text; // 当前类名
      }

      if (ts.isComputedPropertyName(node)) {
        const expr = node.expression;
        // 检查是否为 PropertyAccessExpression 并且是静态成员 C1.x
        if (
          ts.isPropertyAccessExpression(expr) &&
          ts.isIdentifier(expr.expression)
        ) {
          const className = expr.expression.text;
          const { line, character } = astRoot.getLineAndCharacterOfPosition(
            node.getStart()
          );
          const posion = LineColPosition.buildFromNode(
            expr.expression,
            astRoot
          );

          // 确保类 C1 已定义
          if (
            className !== currentClassName ||
            !classDeclarations.has(className) ||
            (classDeclarations.has(className) &&
              classDeclarations.get(className)!.line > line)
          ) {
            let isInFunctionBody = false;

            errors.set(className, {
              line: posion.getLineNo(),
              column: posion.getColNo(),
              inFun: isInFunctionBody,
            });
          }
        }
      }
      ts.forEachChild(node, (childNode) =>
        checkComputedPropertyUsage(childNode, currentClassName)
      );
    };

    // 检查静态属性初始化器是否引用了类本身
    const checkStaticPropertyInitializer = (
      node: ts.Node,
      astRoot: ts.SourceFile,
      className: string,
      errors: Map<string, { line: number; column: number; inFun: Boolean }>
    ) => {
      // 检查是否为类的静态属性 x&& node.name.getText() === "x"
      if (ts.isPropertyDeclaration(node)) {
        const initializer = node.initializer;

        // 确保初始化器存在，并且是一个标识符 (如 C3)
        if (initializer && ts.isIdentifier(initializer)) {
          const classReference = initializer.text; // 获取类的引用 C3

          // 检查是否初始化器是类名 C3
          if (
            classReference === className &&
            !havBodyClass.includes(classReference)
          ) {
            // 如果静态属性的初始化器是类名 C3，记录错误
            const position = LineColPosition.buildFromNode(
              initializer,
              astRoot
            );
            errors.set(classReference, {
              line: position.getLineNo(),
              column: position.getColNo(),
              inFun: false,
            });
          }
        }
      }
    };

    // 检查静态块中的类属性赋值
    const checkStaticBlockUsage = (node: ts.Node) => {
      if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
        node.members.forEach((member) => {
          // 静态块处理
          if (ts.isClassStaticBlockDeclaration(member)) {
            member.body.statements.forEach((stmt) => {
              if (
                ts.isExpressionStatement(stmt) &&
                ts.isNewExpression(stmt.expression)
              ) {
                const className = (stmt.expression.expression as ts.Identifier)
                  .text;
                const { line, character } =
                  astRoot.getLineAndCharacterOfPosition(stmt.getStart());
                const posion = LineColPosition.buildFromNode(
                  stmt.expression.expression,
                  astRoot
                );

                // 确保类在静态块中使用时已定义
                if (
                  !classDeclarations.has(className) ||
                  classDeclarations.get(className)!.line > line
                ) {
                  let isInFunctionBody = false;

                  errors.set(className, {
                    line: posion.getLineNo(),
                    column: posion.getColNo(),
                    inFun: isInFunctionBody,
                  });
                }
              } else if (
                ts.isExpressionStatement(stmt) &&
                ts.isBinaryExpression(stmt.expression)
              ) {
                const binaryExpr = stmt.expression as ts.BinaryExpression;
                if (
                  ts.isPropertyAccessExpression(binaryExpr.left) &&
                  ts.isIdentifier(binaryExpr.left.expression)
                ) {
                  const className = binaryExpr.left.expression.text;
                  const { line, character } =
                    astRoot.getLineAndCharacterOfPosition(stmt.getStart());
                  const posion = LineColPosition.buildFromNode(
                    binaryExpr.left.expression,
                    astRoot
                  );
                  if (
                    !havBodyClass.includes(className) ||
                    classDeclarations.get(className)!.line > line
                  ) {
                    // 判断父节点是否是函数体内的节点
                    let isInFunctionBody = false;

                    errors.set(className, {
                      line: posion.getLineNo(),
                      column: posion.getColNo(),
                      inFun: isInFunctionBody,
                    });
                  }
                }
              }
            });
          }
        });
      }
      ts.forEachChild(node, checkStaticBlockUsage);
    };

    // 先记录 class 定义
    recordClassDeclarations(astRoot);
    // 再检查 class 使用情况
    checkClassUsage(astRoot);

    return errors;
  }

  //获取有类体的类
  private getClassNames(astRoot: ts.SourceFile): string[] {
    const classNames: string[] = [];

    const recordClassNames = (node: ts.Node) => {
      // 检查是否是类声明
      if (ts.isClassExpression(node) && node.name) {
        // 只记录类名，不记录继承的类
        const className = node.name.text;
        classNames.push(className);
      }

      ts.forEachChild(node, recordClassNames); // 递归遍历 AST
    };

    // 处理 AST
    recordClassNames(astRoot);

    return classNames;
  }
  //获取片段内某段位置
  private getAccuratePosition(codeImport: string, name: string) {
    const lines = codeImport.split("\n");

    // 转义 name 中的正则特殊字符
    const escapedName = name.replace(/[.*+?^=!:${}()|\[\]\/\\]/g, "\\$&");

    // 使用正则，确保匹配完整的标识符（前后是非字母数字或下划线）
    const regex = new RegExp(`\\b${escapedName}\\b`, "g");

    for (let i = 0; i < lines.length; i++) {
      let match;
      while ((match = regex.exec(lines[i])) !== null) {
        return { line: i + 1, col: match.index + 1 }; // 返回行号和列号
      }
    }

    return { line: -1, col: -1 }; // 未找到
  }

  //获取调用链首个位置名称
  private extractFunctionName(str: string): string {
    // 去掉所有括号 "()"
    str = str.replace(/\(\)/g, "");

    // 先按 "." 分割，并取第一个部分
    const firstPart = str.split(".")[0];

    // 再按 " " 分割，取最后一个非空单词
    const parts = firstPart.trim().split(" ");
    return parts[parts.length - 1]; // 取最后一个单词
  }

  private getFileExtension(filePath: string, filetype: string): boolean {
    // 使用正则表达式匹配文件后缀
    const match = filePath.match(/\.([0-9a-zA-Z]+)$/);

    // 如果匹配到了扩展名，且扩展名等于 filetype，则返回扩展名，否则返回空字符串
    if (match) {
      const extension = match[1];
      return extension === filetype;
    }

    return false;
  }
}
